package com.uniovi.nmapgui;



import java.io.*;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;


import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uniovi.nmapgui.nmap.controller.CommandnestedController;
import com.uniovi.nmapgui.nmap.entity.Commandnested;
import com.uniovi.nmapgui.nmap.entity.Task;
import com.uniovi.nmapgui.nmap.entity.TaskIp;
import com.uniovi.nmapgui.nmap.mapper.CommandnestedMapper;
import com.uniovi.nmapgui.nmap.service.ICommandnestedService;
import com.uniovi.nmapgui.nmap.service.ITaskIpService;
import com.uniovi.nmapgui.nmap.service.ITaskService;
import com.uniovi.nmapgui.quartz.StartOfDayJob;
import com.uniovi.nmapgui.quartz.service.JobService;
import com.uniovi.nmapgui.util.R;
import org.joda.time.DateTime;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.uniovi.nmapgui.executor.CommandExecutor;
import com.uniovi.nmapgui.executor.CommandExecutorImpl;
import com.uniovi.nmapgui.executor.CommandExecutorObserver;
import com.uniovi.nmapgui.model.Command;
import com.uniovi.nmapgui.util.Filefinder;

@Controller
public class WebController implements CommandExecutorObserver{
	private List<Command> ongoingCommands  = new ArrayList<Command>();
	private List<Command> finishedCommands = new ArrayList<Command>();
	private Command command;
	private boolean finishedCommandQueued=true;
	private InitialConfigurator config = new InitialConfigurator();

	//用来保存每个任务的  副表属性
	private Task task = new Task();

	@Resource
	CommandnestedMapper commandnestedMapper;
	@Autowired
	ICommandnestedService iCommandnestedServiceImpl;
	@Autowired
	ITaskIpService taskIpServiceImpl;
	@Autowired
	ITaskService taskServiceImpl;
	@Value("${fileUrl}")
	String fileUrl;

	@PostConstruct
	public void init(){
		config.configure();
	}
	
    @GetMapping("/nmap")
    public String command(Model model) {

    	command = new Command();
    	model.addAttribute("command", command);
    	model.addAttribute("scriptCategories", config.getScriptCategories());
    	model.addAttribute("menu", config.getMenu());
    	model.addAttribute("commands", ongoingCommands);
    	model.addAttribute("commands", finishedCommands);
    	finishedCommandQueued=true;
        return "index";
    }
    
    @GetMapping("/nmap-exe")
    public String command(Model model, @RequestParam String code) {
    	command =  new Command(code);
    	ongoingCommands.add(0,command);
    	executeCommand(command,"","");
    	model.addAttribute("command", command);
    	model.addAttribute("commands", ongoingCommands);
    	
        return "fragments/contents :: ongoing";
    }
    
    @GetMapping("/nmap/removeCommand")
    public String removeCommand(Model model, @RequestParam int index) {
    	finishedCommands.remove(index);
    	model.addAttribute("command", command);
    	model.addAttribute("finishedCommands", finishedCommands);
        return "fragments/contents :: finished";
    }
    
    
    @GetMapping("/nmap/update")
    public String updateOut(Model model) {  
    	
    	model.addAttribute("command", command);
    	model.addAttribute("commands", ongoingCommands);
    	return "fragments/contents :: ongoing";
    }
    
    @GetMapping("/nmap/update-finished")
    public String updateEnded(Model model) {

		//将nmap原生封装信息保留
		//iCommandnestedServiceImpl.saveToMysql(finishedCommands);
		task.setStatus(0);
		iCommandnestedServiceImpl.saveToMysqlNew(command,task);
		List<Command> finishedCommands = iCommandnestedServiceImpl.changeCommandnestTOCommand(iCommandnestedServiceImpl.list());
		for(int i = 0 ; i < finishedCommands.size() ; i++){
			model.addAttribute("command", command);
		}
		model.addAttribute("finishedCommands", finishedCommands);
		finishedCommandQueued=false;

    	return "fragments/contents :: finished";
    }

    @GetMapping("/nmap/finishedQueued")
    public @ResponseBody Boolean updateEnd() {
    	return finishedCommandQueued;
    }
    @GetMapping("/nmap/stopUpdating")
    public @ResponseBody Boolean stopUpdating() {
    	return ongoingCommands.isEmpty();
    }
    
    @GetMapping("/nmap/download/{filename}")
    public ResponseEntity<InputStreamResource> download(@PathVariable("filename") String filename) {
    	
    	InputStream file;
		try {
			file = new Filefinder().find(filename);
			InputStreamResource resource = new InputStreamResource(file);

	        return ResponseEntity.ok()
	                .contentType(MediaType.parseMediaType("application/octect-stream"))
	                .body(resource);
		} catch (FileNotFoundException e) {
			return ResponseEntity.notFound().build();
		}
    }

    //新接口  统一加入new 标识
	//新接口  添加
	@GetMapping("/newNmap-exe")
	@ResponseBody
	public synchronized R newNmapexe(@RequestParam String code,String summary,Integer taskid) {

		command =  new Command(code);
		ongoingCommands.add(0,command);
		executeCommand(command,summary,code,taskid);
		return R.ok();
	}

	//运行完之后 将运行状态保存
	//@GetMapping("/nmap/taskFinished")
	@ResponseBody
	public  R taskFinished() {

		task.setStatus(0);
		iCommandnestedServiceImpl.saveToMysqlNew(command,task);
		finishedCommandQueued=false;
		return R.ok();
	}

	//定时函数  每秒执行一次  验证 当前任务是否执行完毕
	//重写
	@Scheduled(cron="0/1 * *  * * ? ")   //每1秒执行一次  //备案返回
	public void aTask(){

		//选择在一个小时以内添加并且未完成的任务，
		DateTime now = new DateTime();
		now = now.plusHours(-1);
		QueryWrapper<Task> queryWrapper = new QueryWrapper();
		//System.out.println(now.plusHours(-1));
		//queryWrapper.between("starttime",now.plusHours(-1),now);
		queryWrapper.isNull("endtime");
		queryWrapper.apply("UNIX_TIMESTAMP(starttime) >= UNIX_TIMESTAMP('" + now + "')");
		List<Task> tasks = taskServiceImpl.list(queryWrapper);
		//以taskid查看 commandnested表中
		for (int i = 0 ; i < tasks.size() ; i++){

			File file = new File(tasks.get(i).getFilename()+".nmap");
			if (file.exists()&&file.length()>1500){

				Reader reader = null;
				StringBuffer text =new StringBuffer();
				try {
					//System.out.println("以字符为单位读取文件内容，一次读一个字节：");
					// 一次读一个字符
					reader = new InputStreamReader(new FileInputStream(file));
					int tempchar;
					while ((tempchar = reader.read()) != -1) {
						// 对于windows下，\r\n这两个字符在一起时，表示一个换行。
						// 但如果这两个字符分开显示时，会换两次行。
						// 因此，屏蔽掉\r，或者屏蔽\n。否则，将会多出很多空行。
						if (((char) tempchar) != '\r') {
							text.append((char) tempchar);
						}
					}
					reader.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
				iCommandnestedServiceImpl.saveToMysql(text.toString(),tasks.get(i));
			}


		}
	}

	//@Scheduled(cron="0/1 * *  * * ? ")   //每1秒执行一次   镁拓返回
	public void aTask2(){

		if(stopUpdating()){
			taskFinished();
		}
	}
	//定时将未完成的扫描任务返回（备案）
	@Scheduled(cron="0/30 * *  * * ? ")
	public void undone() {


		iCommandnestedServiceImpl.undone();

	}

	@Override
    public void finishedCommand(Command cmd){
        ongoingCommands.remove(cmd);
        finishedCommands.add(0,cmd);
        finishedCommandQueued = true;
    }

    public void executeCommand(Command command,String summary,String code){
		//初始化 task
		task = new Task();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		task.setStarttime(simpleDateFormat.format(new Date()));
		task.setFilename(fileUrl+"/"+UUID.randomUUID().toString());
		task.setSummary(summary);
		task.setCode(code);
		task.setStatus(1);
		task.setCommand(UUID.randomUUID().toString());
		//将task入库
		if (task!=null && taskServiceImpl.count(new QueryWrapper<>(task))==0){
			taskServiceImpl.save(task);
		}
    	CommandExecutor executor = new CommandExecutorImpl(command,task,commandnestedMapper);
    	executor.addObserver(this);
    	executor.execute();
    }

	public void executeCommand(Command command,String summary,String code,int taskid){

		//初始化 task
		task = new Task();
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		task.setTasknewid(taskid);
		task.setStarttime(simpleDateFormat.format(new Date()));
		task.setFilename(fileUrl+"/"+UUID.randomUUID().toString());
		task.setSummary(summary);
		task.setCode(code);
		task.setStatus(1);
		task.setCommand(UUID.randomUUID().toString());
		//将task入库
		if (task!=null && taskServiceImpl.count(new QueryWrapper<>(task))==0){
			taskServiceImpl.save(task);
		}
		CommandExecutor executor = new CommandExecutorImpl(command,task,commandnestedMapper);
		executor.addObserver(this);
		executor.execute();
	}

	public static void main(String[] args) {
		File file = new File("D:\\workspace6\\ifast-website-bei-an\\target\\6183b057-c20b-46da-8dde-d3bbe6528f63.gnmap");
		if (file.exists()){

			System.out.println(file.length());
		}
	}

}
